/*
 * Copyright (c) 2010 Vadim Zhukov <persgray@gmail.com>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */


#ifndef OW_SENSOR_H
#define OW_SENSOR_H

#include "sensor_params.h"


/* Those values include terminating '\0' */
enum { SENSOR_MAXNAME = 256 };      /* XXX: Align on 64 bits for wd_condition */
enum { SENSOR_MAXVALUE = 1024 };

TAILQ_HEAD(wsensor_list, wsensor);
struct wsensor {
	TAILQ_ENTRY(wsensor)	entry;
	int	flags;
	int	fd;
	char	name[SENSOR_MAXNAME];

	/*
	 * Points to the string after "/sensor/TYPE/" in the name. May be empty
	 * string but not NULL or non-nul-terminated. Set by sensor_init().
	 */
	const char	*params;

	/* Internals below. Should not be touched outside of sensor.c */

	/* Cache routine lookup */
	int	(*get_line)(struct wsensor *, struct log_msg *);
	union	sensor_params sp;
};

enum {
	/*
	 * Gauge sensors always have some value, instead of collecting sensors
	 * that acquire data from somewhere else.
	 *
	 * Set by sensor_init().
	 */
	SENSOR_F_GAUGE = 0x01,

	/*
	 * Indicates that "fd" member can be used for polling.
	 *
	 * Set by sensor_init().
	 */
	SENSOR_F_POLLABLE = 0x02,

	/*
	 * Indicates that sensor could be simply poll()'ed instead of requesting
	 * each time. If all enabled sensors are poll()'able then we can poll()
	 * without timeout value.
	 *
	 * Set by sensor_init().
	 */
	SENSOR_F_POLLONLY = 0x04,

	/*
	 * Indicates that sensor should be used only for watchdogs. log_msg
	 * structures returned by get_sensor_line() will NOT have
	 * LOG_MSG_ACTION_LOG flag set.
	 *
	 * Set by user.
	 */
	SENSOR_F_NOLOG  = 0x08,
};

#define sensor_is_pollable(s)	((s)->flags & SENSOR_F_POLLABLE)
#define sensor_is_pollonly(s)	((s)->flags & SENSOR_F_POLLONLY)
#define sensor_is_gauge(s)	((s)->flags & SENSOR_F_GAUGE)

SLIST_HEAD(wd_action_list, wd_action);
struct wd_action {
	SLIST_ENTRY(wd_action)	entry;
	int	 code;
	int	 sig;
	uid_t	 uid;
	char	*s;	/* Should be nul-terminated */
};

enum {
	WD_ACTION_KILL_NAME,		/* Kill processes by name pattern */
	WD_ACTION_KILL_PIDFILE,		/* Kill processes by PIDs from file */
	WD_ACTION_RUN_CMD,		/* Run command via system(3) */
};

SLIST_HEAD(wd_condition_list, wd_condition);
struct wd_condition {
	SLIST_ENTRY(wd_condition)	entry;

	/*
	 * Watchdog acts only if situation does not change for n seconds.
	 * Set to zero for immediate reaction.
	 */
	time_t	 minduration;

	/*
	 * Mark when the condition evaluated to true first time.
	 * Reset to zero on every non-match.
	 */
	time_t	 first;

	int	 op;

	/*
	* Sensor name (template) that current condition is applicable to.
	*/
	char	 sens_name[SENSOR_MAXNAME];

	/*
	 * Compare stuff. Cannot use union because "s" does not have known size.
	 */
	int	 n;
	int	 n2;
	char	*s;		/* Should be null-terminated */
};

enum {
	WD_CMP_NUM_EQ,
	WD_CMP_NUM_GE,
	WD_CMP_NUM_GT,
	WD_CMP_NUM_LE,
	WD_CMP_NUM_LT,
	WD_CMP_NUM_NE,
	WD_CMP_NUM_IN,
	WD_CMP_NUM_OUT,
	WD_CMP_STR_EQ,
	WD_CMP_STR_EQ_NC,
	WD_CMP_STR_NEQ,
	WD_CMP_STR_NEQ_NC,
	WD_CMP_STR_MATCH,
	WD_CMP_STR_MATCH_NC,
	WD_CMP_STR_NMATCH,
	WD_CMP_STR_NMATCH_NC,
};

TAILQ_HEAD(watchdog_list, watchdog);
struct watchdog {
	TAILQ_ENTRY(watchdog)		entry;
	struct wd_condition_list	conditions;
	struct wd_action_list		actions;
	char	name[SENSOR_MAXNAME];
};


int		 sensor_init(struct wsensor *);
int		 sensor_uninit(struct wsensor *);
struct log_msg	*sensor_get_line(struct wsensor *);
int		 sensor_convert_log_line(const char *, size_t,
		    struct log_msg *);

struct watchdog	*watchdog_new(void);
void		 watchdog_free(struct watchdog *);
int		 watchdog_from_spec(struct watchdog *, const char *);
void		 watchdog_check(const struct watchdog *, const struct wsensor *,
		    struct log_msg *);

#endif /* OW_SENSOR_H */
